/*
 * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
 *
 * SPDX-License-Identifier: Unlicense OR CC0-1.0
 */

/****************************************************************************
*
* This demo showcases creating a GATT database using a predefined attribute table.
* It acts as a GATT server and can send adv data, be connected by client.
* Run the gatt_client demo, the client demo will automatically connect to the gatt_server_service_table demo.
* Client demo will enable GATT server's notify after connection. The two devices will then exchange
* data.
*
****************************************************************************/
#include "gatts_table_creat_demo.h"

/* 
    如果蓝牙传来的数据不包含key，默认是ecu配置通讯协议，转发至串口。 
    If the data transmitted from Bluetooth does not contain a key, the default is to configure the communication protocol in the ecu and forward it to the serial port.
    to_uart_len:data length
    write_to_serial: data
*/

//  Queue
QueueHandle_t QHandle;

uint64_t avgrate;

/* key value */
static char keyval[32] = "beike0531";

/* get from ble 's config data*/
static uint32_t ble_value_index;
static uint8_t wif_config_data[256];

static uint8_t adv_config_done = 0;

uint16_t heart_rate_handle_table[HRS_IDX_NB];

static prepare_type_env_t prepare_write_env;

static TaskHandle_t THhanle;

struct get_serial_ecuinfo ecuinfo;

/* 
    控制esp32的重启
    Control the restart of esp32
 */
static int my_restart = 0;

#define CONFIG_SET_RAW_ADV_DATA
#ifdef CONFIG_SET_RAW_ADV_DATA
static uint8_t raw_adv_data[] = {
        /* 
            flags 
            表示Flags，数据0x06表示LE通用发现模式，不支持BR/EDR。
        */
        0x02, 0x01, 0x06,
        /* 
            tx power
            表示发射功率等级，数据0xeb表示功率等级为-21。
        */
        0x02, 0x0a, 0xeb,
        /* 
            service 
            表示完整的16位uuid列表，数据0xab 0xcd表示uuid为0xcdab。    
        uuid */
        0x03, 0x03, 0xFF, 0x00,
        /* device name */
        0x0f, 0x09, 'E', 'S', 'P', '_', 'G', 'A', 'T', 'T', 'S', '_', 'D','E', 'M', 'O'
};

static uint8_t raw_scan_rsp_data[] = {
        /* flags */
        0x02, 0x01, 0x06,
        /* tx power */
        0x02, 0x0a, 0xeb,
        /* service uuid */
        0x03, 0x03, 0xFF,0x00
};

#else
static uint8_t service_uuid[16] = {
    /* LSB <--------------------------------------------------------------------------------> MSB */
    //first uuid, 16bit, [12],[13] is the value
    0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
};

/* The length of adv data must be less than 31 bytes */
static esp_ble_adv_data_t adv_data = {
    .set_scan_rsp        = false,
    .include_name        = true,
    .include_txpower     = true,
    .min_interval        = 0x0006, //slave connection min interval, Time = min_interval * 1.25 msec
    .max_interval        = 0x0010, //slave connection max interval, Time = max_interval * 1.25 msec
    .appearance          = 0x00,
    .manufacturer_len    = 0,    //TEST_MANUFACTURER_DATA_LEN,
    .p_manufacturer_data = NULL, //test_manufacturer,
    .service_data_len    = 0,
    .p_service_data      = NULL,
    .service_uuid_len    = sizeof(service_uuid),
    .p_service_uuid      = service_uuid,
    .flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT),
};

// scan response data
static esp_ble_adv_data_t scan_rsp_data = {
    .set_scan_rsp        = true,
    .include_name        = true,
    .include_txpower     = true,
    .min_interval        = 0x0006,
    .max_interval        = 0x0010,
    .appearance          = 0x00,
    .manufacturer_len    = 0, //TEST_MANUFACTURER_DATA_LEN,
    .p_manufacturer_data = NULL, //&test_manufacturer[0],
    .service_data_len    = 0,
    .p_service_data      = NULL,
    .service_uuid_len    = sizeof(service_uuid),
    .p_service_uuid      = service_uuid,
    .flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT),
};
#endif /* CONFIG_SET_RAW_ADV_DATA */

static esp_ble_adv_params_t adv_params = {
    .adv_int_min         = 0x20,
    .adv_int_max         = 0x40,
    .adv_type            = ADV_TYPE_IND,
    .own_addr_type       = BLE_ADDR_TYPE_PUBLIC,
    .channel_map         = ADV_CHNL_ALL,
    .adv_filter_policy   = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
};

struct gatts_profile_inst {
    esp_gatts_cb_t gatts_cb;
    uint16_t gatts_if;
    uint16_t app_id;
    uint16_t conn_id;
    uint16_t service_handle;
    esp_gatt_srvc_id_t service_id;
    uint16_t char_handle;
    esp_bt_uuid_t char_uuid;
    esp_gatt_perm_t perm;
    esp_gatt_char_prop_t property;
    uint16_t descr_handle;
    esp_bt_uuid_t descr_uuid;
};

void getInitFileData(struct esp_device_config *temp_init);

void handle_esp_blufi_data(uint8_t *data,uint32_t len);

static void gatts_profile_event_handler(esp_gatts_cb_event_t event,
					esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param);

/* One gatt-based profile one app_id and one gatts_if, this array will store the gatts_if returned by ESP_GATTS_REG_EVT */
static struct gatts_profile_inst heart_rate_profile_tab[PROFILE_NUM] = {
    [PROFILE_APP_IDX] = {
        .gatts_cb = gatts_profile_event_handler,
        .gatts_if = ESP_GATT_IF_NONE,       /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */
    },
};

/* Service */
static const uint16_t GATTS_SERVICE_UUID_TEST      = 0x00FF;
static const uint16_t GATTS_CHAR_UUID_TEST_A       = 0xFF01;
static const uint16_t GATTS_CHAR_UUID_TEST_B       = 0xFF02;
static const uint16_t GATTS_CHAR_UUID_TEST_C       = 0xFF03;

static const uint16_t primary_service_uuid         = ESP_GATT_UUID_PRI_SERVICE;
static const uint16_t character_declaration_uuid   = ESP_GATT_UUID_CHAR_DECLARE;
static const uint16_t character_client_config_uuid = ESP_GATT_UUID_CHAR_CLIENT_CONFIG;
static const uint8_t char_prop_read                =  ESP_GATT_CHAR_PROP_BIT_READ;
static const uint8_t char_prop_write               = ESP_GATT_CHAR_PROP_BIT_WRITE;
static const uint8_t char_prop_read_write_notify   = ESP_GATT_CHAR_PROP_BIT_WRITE | ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_NOTIFY;
static const uint8_t heart_measurement_ccc[2]      = {0x00, 0x00};
static const uint8_t char_value[4]                 = {0x11, 0x22, 0x33, 0x44};

/* 
    Full Database Description - Used to add attributes into the database 
    Full HRS 数据库描述 - 用于将属性添加到数据库中 
*/
const esp_gatts_attr_db_t gatt_db[HRS_IDX_NB] =
{
    // Service Declaration
    [IDX_SVC]        =
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&primary_service_uuid, ESP_GATT_PERM_READ,
      sizeof(uint16_t), sizeof(GATTS_SERVICE_UUID_TEST), (uint8_t *)&GATTS_SERVICE_UUID_TEST}},

    /* Characteristic Declaration */
    [IDX_CHAR_A]     =
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ,
      CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_read_write_notify}},

    /* Characteristic Value */
    [IDX_CHAR_VAL_A] =
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&GATTS_CHAR_UUID_TEST_A, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
      GATTS_DEMO_CHAR_VAL_LEN_MAX, sizeof(char_value), (uint8_t *)char_value}},

    /* Client Characteristic Configuration Descriptor */
    [IDX_CHAR_CFG_A]  =
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_client_config_uuid, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
      sizeof(uint16_t), sizeof(heart_measurement_ccc), (uint8_t *)heart_measurement_ccc}},

    /* Characteristic Declaration */
    [IDX_CHAR_B]      =
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ,
      CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_read}},

    /* Characteristic Value */
    [IDX_CHAR_VAL_B]  =
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&GATTS_CHAR_UUID_TEST_B, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
      GATTS_DEMO_CHAR_VAL_LEN_MAX, sizeof(char_value), (uint8_t *)char_value}},

    /* Characteristic Declaration */
    [IDX_CHAR_C]      =
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ,
      CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_write}},

    /* Characteristic Value */
    [IDX_CHAR_VAL_C]  =
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&GATTS_CHAR_UUID_TEST_C, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
      GATTS_DEMO_CHAR_VAL_LEN_MAX, sizeof(char_value), (uint8_t *)char_value}},

};

/*
    定义了在广播期间蓝牙设备的一些操作，蓝牙是通过GAP建立通信的
*/
void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{
    switch (event) {
    #ifdef CONFIG_SET_RAW_ADV_DATA
        case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT:
            adv_config_done &= (~ADV_CONFIG_FLAG);
            if (adv_config_done == 0){
                esp_ble_gap_start_advertising(&adv_params);
            }
            break;
        case ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT:
            adv_config_done &= (~SCAN_RSP_CONFIG_FLAG);
            if (adv_config_done == 0){
                esp_ble_gap_start_advertising(&adv_params);
            }
            break;
    #else
        case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT:
            adv_config_done &= (~ADV_CONFIG_FLAG);
            if (adv_config_done == 0){
                esp_ble_gap_start_advertising(&adv_params);
            }
            break;
        case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT:                            //广播数据设置完成事件标志
            adv_config_done &= (~SCAN_RSP_CONFIG_FLAG);
            if (adv_config_done == 0){
                esp_ble_gap_start_advertising(&adv_params);
            }
            break;
    #endif
        case ESP_GAP_BLE_ADV_START_COMPLETE_EVT:                                    //开始广播事件标志
            /* advertising start complete event to indicate advertising start successfully or failed */
            if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) {
                ESP_LOGE(GATTS_TABLE_TAG, "advertising start failed");
            }else{
                ESP_LOGI(GATTS_TABLE_TAG, "advertising start successfully");
            }
            break;
        case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT:                                     //停止广播事件标志
            if (param->adv_stop_cmpl.status != ESP_BT_STATUS_SUCCESS) {
                ESP_LOGE(GATTS_TABLE_TAG, "Advertising stop failed");
            }
            else {
                ESP_LOGI(GATTS_TABLE_TAG, "Stop adv successfully\n");
            }
            break;
        case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT:                                    // 设备连接事件,可获取当前连接的设备信息
            ESP_LOGI(GATTS_TABLE_TAG, "update connection params status = %d, min_int = %d, max_int = %d,conn_int = %d,latency = %d, timeout = %d",
                  param->update_conn_params.status,
                  param->update_conn_params.min_int,
                  param->update_conn_params.max_int,
                  param->update_conn_params.conn_int,
                  param->update_conn_params.latency,
                  param->update_conn_params.timeout);
            break;
        default:
            break;
    }
}

void example_prepare_write_event_env(esp_gatt_if_t gatts_if, prepare_type_env_t *prepare_write_env, esp_ble_gatts_cb_param_t *param)
{
    ESP_LOGI(GATTS_TABLE_TAG, "prepare write, handle = %d, value len = %d", param->write.handle, param->write.len);
    esp_gatt_status_t status = ESP_GATT_OK;
    if (prepare_write_env->prepare_buf == NULL) {
        prepare_write_env->prepare_buf = (uint8_t *)malloc(PREPARE_BUF_MAX_SIZE * sizeof(uint8_t));
        prepare_write_env->prepare_len = 0;
        if (prepare_write_env->prepare_buf == NULL) {
            ESP_LOGE(GATTS_TABLE_TAG, "%s, Gatt_server prep no mem", __func__);
            status = ESP_GATT_NO_RESOURCES;
        }
    } else {
        if(param->write.offset > PREPARE_BUF_MAX_SIZE) {
            status = ESP_GATT_INVALID_OFFSET;
        } else if ((param->write.offset + param->write.len) > PREPARE_BUF_MAX_SIZE) {
            status = ESP_GATT_INVALID_ATTR_LEN;
        }
    }
    /*send response when param->write.need_rsp is true */
    if (param->write.need_rsp){
        esp_gatt_rsp_t *gatt_rsp = (esp_gatt_rsp_t *)malloc(sizeof(esp_gatt_rsp_t));
        if (gatt_rsp != NULL){
            gatt_rsp->attr_value.len = param->write.len;
            gatt_rsp->attr_value.handle = param->write.handle;
            gatt_rsp->attr_value.offset = param->write.offset;
            gatt_rsp->attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE;
            memcpy(gatt_rsp->attr_value.value, param->write.value, param->write.len);
            esp_err_t response_err = esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, status, gatt_rsp);
            if (response_err != ESP_OK){
               ESP_LOGE(GATTS_TABLE_TAG, "Send response error");
            }
            free(gatt_rsp);
        }else{
            ESP_LOGE(GATTS_TABLE_TAG, "%s, malloc failed", __func__);
        }
    }
    if (status != ESP_GATT_OK){
        return;
    }
    memcpy(prepare_write_env->prepare_buf + param->write.offset,
           param->write.value,
           param->write.len);
    prepare_write_env->prepare_len += param->write.len;

}

void example_exec_write_event_env(prepare_type_env_t *prepare_write_env, esp_ble_gatts_cb_param_t *param){
    if (param->exec_write.exec_write_flag == ESP_GATT_PREP_WRITE_EXEC && prepare_write_env->prepare_buf){
        esp_log_buffer_hex(GATTS_TABLE_TAG, prepare_write_env->prepare_buf, prepare_write_env->prepare_len);
    }else{
        ESP_LOGI(GATTS_TABLE_TAG,"ESP_GATT_PREP_WRITE_CANCEL");
    }
    if (prepare_write_env->prepare_buf) {
        free(prepare_write_env->prepare_buf);
        prepare_write_env->prepare_buf = NULL;
    }
    prepare_write_env->prepare_len = 0;
}

int ASCII_To_Hex(int number){
    if (number >= '0' && number <= '9')
		return (number - 0x30);
 
	else if (number >= 'a' && number <= 'f')
		return ((number - 'a') + 10);
	
	else if (number >= 'A' && number <= 'F')
		return ((number - 'A') + 10);
 
	return (0);
}

void handle_buffer(uint8_t *buffer,int len){
    /*
        声明结构体指针，用来处理从蓝牙发送的{85 14 16 50 00 00 00 00 AF 1E}类型设置数据
        我们只需要保存{}内的数据，其中只有车牌设置数据有19个字节，其他设置数据只有10个字节。
    */
    struct ecu_to_serial ets;

    memset(&ets.data[0],0,ECU_DATA_LEN);

    int cone;
    int ctwo;
    uint8_t *p;
    int t = 0;

    p = buffer;

    ets.len = 0;

    for(int i = 0;i < len ;i+=3){
        ets.len++;

        if((*p <= '9' && *p >= '0') || ('A' <= *p && *p <= 'F') || ('a' <= *p && *p <= 'f')){
            ;
        }else{
            ets.len = 0;
            return;
        }

        cone = *p++;
        
        if((*p <= '9' && *p >= '0') || ('A' <= *p && *p <='F') || ('a' <= *p && *p <= 'f')){
            ;
        }else{
            ets.len = 0;
            return;
        }

        ctwo = *p++;

        if(*p != '\0'){
            if(*p != ' '){
                ets.len = 0;
                return;
            }
        }

        cone = ASCII_To_Hex(cone);
        ctwo = ASCII_To_Hex(ctwo);

        ets.data[t] = cone << 0x04 | ctwo;

        t++;
        p++;
    }

    xQueueSend(QHandle, (void *)&ets, 0);

    return;
}

static void THread_task(void *parm){
    while(1){
        if(ecuinfo.ble_flag == 1){
            ecuinfo.ecu_info[ecuinfo.len] = 0xFE;
            ecuinfo.ecu_info[ecuinfo.len-3] = led_control_flag;
            esp_ble_gatts_set_attr_value(45,ecuinfo.len+1,(uint8_t*)ecuinfo.ecu_info);
            ecuinfo.ecu_info[ecuinfo.len] = 0;
            ecuinfo.ecu_info[ecuinfo.len-3] = 0xFE;
            ecuinfo.ble_flag = 0;
        }   
        vTaskDelay(300 / portTICK_PERIOD_MS);
    }
}

/*
    GATT (通用属性配置) ，它定义两个 BLE 设备通过 Service 和 Characteristic 进行通信；

    GATT 就是使用了 ATT（Attribute Protocol）协议，ATT层定义了一个通信的基本框架，数据的基本结构，以及通信的指令，Service 和 characteristic 就是GATT层定义的， GATT层用来赋予每个数据一个具体的内涵，让数据变得有结构和意义。
*/
void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
{
    switch (event) {
            /*
                展示了一个Service的创建
                GATT注册事件，添加 service的基本信息，设置BLE名称
            */
        case ESP_GATTS_REG_EVT:{
            esp_err_t set_dev_name_ret = esp_ble_gap_set_device_name(SAMPLE_DEVICE_NAME);
            if (set_dev_name_ret){
                ESP_LOGE(GATTS_TABLE_TAG, "set device name failed, error code = %x", set_dev_name_ret);
            }
    #ifdef CONFIG_SET_RAW_ADV_DATA
            esp_err_t raw_adv_ret = esp_ble_gap_config_adv_data_raw(raw_adv_data, sizeof(raw_adv_data));
            if (raw_adv_ret){
                ESP_LOGE(GATTS_TABLE_TAG, "config raw adv data failed, error code = %x ", raw_adv_ret);
            }
            adv_config_done |= ADV_CONFIG_FLAG;
            esp_err_t raw_scan_ret = esp_ble_gap_config_scan_rsp_data_raw(raw_scan_rsp_data, sizeof(raw_scan_rsp_data));
            if (raw_scan_ret){
                ESP_LOGE(GATTS_TABLE_TAG, "config raw scan rsp data failed, error code = %x", raw_scan_ret);
            }
            adv_config_done |= SCAN_RSP_CONFIG_FLAG;
    #else
            //config adv data
            esp_err_t ret = esp_ble_gap_config_adv_data(&adv_data);
            if (ret){
                ESP_LOGE(GATTS_TABLE_TAG, "config adv data failed, error code = %x", ret);
            }
            adv_config_done |= ADV_CONFIG_FLAG;
            //config scan response data
            ret = esp_ble_gap_config_adv_data(&scan_rsp_data);
            if (ret){
                ESP_LOGE(GATTS_TABLE_TAG, "config scan response data failed, error code = %x", ret);
            }
            adv_config_done |= SCAN_RSP_CONFIG_FLAG;
    #endif
            esp_err_t create_attr_ret = esp_ble_gatts_create_attr_tab(gatt_db, gatts_if, HRS_IDX_NB, SVC_INST_ID);
            if (create_attr_ret){
                ESP_LOGE(GATTS_TABLE_TAG, "create attr table failed, error code = %x", create_attr_ret);
            }
        }
       	    break;
        case ESP_GATTS_READ_EVT:
            // ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_READ_EVT, conn_id %d, trans_id %d, handle %d\n", 
            //                             param->read.conn_id, param->read.trans_id, param->read.handle);
            // if(heart_rate_handle_table[IDX_CHAR_VAL_B] == param->read.handle){
            //     uint8_t kakaa_dats[] = "kakaa read value!";
            //     //the size of kakaa_dats[] need less than MTU size
            //     esp_ble_gatts_set_attr_value(param->read.handle,sizeof(kakaa_dats),(uint8_t*)kakaa_dats);
            // }
        break;
        case ESP_GATTS_WRITE_EVT:
            if (!param->write.is_prep){
                // the data length of gattc write  must be less than GATTS_DEMO_CHAR_VAL_LEN_MAX.
                ESP_LOGI(GATTS_TABLE_TAG, "GATT_WRITE_EVT, handle = %d, value len = %d, value :", param->write.handle, param->write.len);
                
                if(strcmp((char *)param->write.value,"clear") == 0){
                    memset(param->write.value,0,256);
                    ble_value_index = 0;
                }

                for(int i = 0 ;i < ble_get_value_max;i++){
                    if(wif_config_data[0] == '{'){
                        if(param->write.value[i] == '}'){
                            wif_config_data[ble_value_index] = param->write.value[i];
                            handle_esp_blufi_data(wif_config_data,ble_value_index+1);
                            ble_value_index = 0;
                            if(my_restart == 1){
                                esp_restart();
                            }
                            break;
                        }else{
                            wif_config_data[ble_value_index] = param->write.value[i];
                            ble_value_index++;
                        }
                    }else{
                        if(param->write.value[i] == '{' ){
                            wif_config_data[ble_value_index] = param->write.value[i];
                            ble_value_index++;
                        }
                    }
                }
                
            }else{
                /* handle prepare write */
                example_prepare_write_event_env(gatts_if, &prepare_write_env, param);
            }
      	    break;
        case ESP_GATTS_EXEC_WRITE_EVT:
            // the length of gattc prepare write data must be less than GATTS_DEMO_CHAR_VAL_LEN_MAX.
            ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_EXEC_WRITE_EVT");
            example_exec_write_event_env(&prepare_write_env, param);
            break;
        case ESP_GATTS_MTU_EVT:
            ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_MTU_EVT, MTU %d", param->mtu.mtu);
            break;
        case ESP_GATTS_CONF_EVT:
            ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_CONF_EVT, status = %d, attr_handle %d", param->conf.status, param->conf.handle);
            break;
        case ESP_GATTS_START_EVT:
            ESP_LOGI(GATTS_TABLE_TAG, "SERVICE_START_EVT, status %d, service_handle %d", param->start.status, param->start.service_handle);
            break;
        case ESP_GATTS_CONNECT_EVT:
            ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_CONNECT_EVT, conn_id = %d", param->connect.conn_id);
            esp_log_buffer_hex(GATTS_TABLE_TAG, param->connect.remote_bda, 6);
            esp_ble_conn_update_params_t conn_params = {0};
            memcpy(conn_params.bda, param->connect.remote_bda, sizeof(esp_bd_addr_t));
            /* For the iOS system, please refer to Apple official documents about the BLE connection parameters restrictions. */
            conn_params.latency = 0;
            conn_params.max_int = 0x20;    // max_int = 0x20*1.25ms = 40ms
            conn_params.min_int = 0x10;    // min_int = 0x10*1.25ms = 20ms
            conn_params.timeout = 400;    // timeout = 400*10ms = 4000ms
            //start sent the update connection parameters to the peer device.
            esp_ble_gap_update_conn_params(&conn_params);

            xTaskCreate(THread_task, 
                "THread_task", 
                1024*2, 
                NULL, 
                configMAX_PRIORITIES, 
                &THhanle);

            break;
        case ESP_GATTS_DISCONNECT_EVT:
            ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_DISCONNECT_EVT, reason = 0x%x", param->disconnect.reason);
            esp_ble_gap_start_advertising(&adv_params);

            vTaskDelete(THhanle);

            break;
        case ESP_GATTS_CREAT_ATTR_TAB_EVT:{
            if (param->add_attr_tab.status != ESP_GATT_OK){
                ESP_LOGE(GATTS_TABLE_TAG, "create attribute table failed, error code=0x%x", param->add_attr_tab.status);
            }
            else if (param->add_attr_tab.num_handle != HRS_IDX_NB){
                ESP_LOGE(GATTS_TABLE_TAG, "create attribute table abnormally, num_handle (%d) \
                        doesn't equal to HRS_IDX_NB(%d)", param->add_attr_tab.num_handle, HRS_IDX_NB);
            }
            else {
                ESP_LOGI(GATTS_TABLE_TAG, "create attribute table successfully, the number handle = %d\n",param->add_attr_tab.num_handle);
                memcpy(heart_rate_handle_table, param->add_attr_tab.handles, sizeof(heart_rate_handle_table));
                esp_ble_gatts_start_service(heart_rate_handle_table[IDX_SVC]);
            }
            break;
        }
        case ESP_GATTS_STOP_EVT:
        case ESP_GATTS_OPEN_EVT:
        case ESP_GATTS_CANCEL_OPEN_EVT:
        case ESP_GATTS_CLOSE_EVT:
        case ESP_GATTS_LISTEN_EVT:
        case ESP_GATTS_CONGEST_EVT:
        case ESP_GATTS_UNREG_EVT:
        case ESP_GATTS_DELETE_EVT:
        default:
            break;
    }
}


/*
参数说明：
event: 
esp_gatts_cb_event_t 枚举类型，表示调用该回调函数时的事件(或蓝牙的状态)

gatts_if: 
esp_gatt_if_t (uint8_t) 这是GATT访问接口类型，
通常在GATT客户端上不同的应用程序用不同的gatt_if(不同的Application profile对应不同的gatts_if) ，
调用esp_ble_gatts_app_register()时，
注册Application profile 就会有一个gatts_if。

param: esp_ble_gatts_cb_param_t 指向回调函数的参数，是个联合体类型，
不同的事件类型采用联合体内不同的成员结构体。

导入 GATT 的 profiles。
*/
void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
{
    /* 
        If event is register event, store the gatts_if for each profile
        判断是否是 GATT 的注册事件 
    */
    if (event == ESP_GATTS_REG_EVT) {
        if (param->reg.status == ESP_GATT_OK) {
            heart_rate_profile_tab[PROFILE_APP_IDX].gatts_if = gatts_if;
        } else {
            ESP_LOGE(GATTS_TABLE_TAG, "reg app failed, app_id %04x, status %d",
                    param->reg.app_id,
                    param->reg.status);
            return;
        }
    }
    do {
        int idx;
        for (idx = 0; idx < PROFILE_NUM; idx++) {
            /* ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every profile cb function */
            if (gatts_if == ESP_GATT_IF_NONE || gatts_if == heart_rate_profile_tab[idx].gatts_if) {
                if (heart_rate_profile_tab[idx].gatts_cb) {
                    heart_rate_profile_tab[idx].gatts_cb(event, gatts_if, param);
                }
            }
        }
    } while (0);
}

//将八个字符的低四位放到一个int中
void chartouint(char *temp,uint32_t *uintp){
    *uintp = 0;
    for(int i = 0;i < 8;i++){
        if(temp[i] == 0){
            //下方for循环目的是忽略掉低位上的所有0
            for(int j=i;j<8;j++){
                if(temp[j] == 0 && j==7){
                    return ;
                }
            }
        }else{
            *uintp = *uintp<<4;
            *uintp |= ASCII_To_Hex(temp[i]);
        }
    }
}

void getInitFileData(struct esp_device_config *edc)
{
    esp_err_t err;
    nvs_handle_t my_handle;
    size_t len;
    char temp[8];

    err = nvs_open("config", NVS_READWRITE, &my_handle);
    if (err != ESP_OK) {
        ;
    }
    else
    {
        memset(temp,0,8);
        edc->seatbeltSensorId = 0;
        
        len = sizeof(edc->inissid);
        err = nvs_get_str(my_handle, "ssid", edc->inissid, &len);

        len = sizeof(edc->inipassword);
        err = nvs_get_str(my_handle, "password", edc->inipassword, &len);

        err = nvs_get_i32(my_handle, "can_bps", &edc->bpscan);

        err = nvs_get_i32(my_handle, "485_bps", &edc->bps485);

        err = nvs_get_i32(my_handle, "serport", &edc->port);
        
        len = sizeof(edc->serip);
        err = nvs_get_str(my_handle, "serip", edc->serip, &len);

        len = sizeof(temp);
        err = nvs_get_str(my_handle,"seatbeltSensorId",temp,&len);
        chartouint(temp,&edc->seatbeltSensorId);

        err = nvs_get_u8(my_handle, "seatbeltIsUsed", &edc->seatbeltIsUsed);

        err = nvs_get_u8(my_handle, "speedSelect", &edc->speedSelect);

        err = nvs_get_u64(my_handle,"speedfix",&edc->ioSpeedFix);
    }
    return;
}

void handle_esp_blufi_data(uint8_t *data,uint32_t len)
{
    /* nvs handle */
    static nvs_handle_t my_handle;
    //Change data to string format
    char * receiveData = NULL;
    size_t dlen;

    receiveData = (char *)malloc(sizeof(char)*len+1);
    int i = 0;
    for(i = 0; i < len; i++){
        receiveData[i] = data[i];
    }
    receiveData[i] = '\0';

    //Determine wled initther it is JSON fromat data
    cJSON *pJsonRoot = cJSON_Parse(receiveData);

    char key[16];
    char value[16];
    int intvalue = 0;
    if(receiveData != NULL){
        cJSON *pKeyAdress = cJSON_GetObjectItem(pJsonRoot,"KEY");
        cJSON *pNewKeyAdress = cJSON_GetObjectItem(pJsonRoot,"NewKey");
        cJSON *pSsidAdress = cJSON_GetObjectItem(pJsonRoot,"ssid");
        cJSON *pPasswordAdress = cJSON_GetObjectItem(pJsonRoot,"password");
        cJSON *pCanAdress = cJSON_GetObjectItem(pJsonRoot,"can_bps");
        cJSON *p485Adress = cJSON_GetObjectItem(pJsonRoot,"485_bps");
        cJSON *pserIPAdress = cJSON_GetObjectItem(pJsonRoot,"serip");
        cJSON *pserPortAdress = cJSON_GetObjectItem(pJsonRoot,"serport");
        cJSON *psbSensorIdAdress = cJSON_GetObjectItem(pJsonRoot,"seatbeltSensorId");
        cJSON *psbIsUsedAdress = cJSON_GetObjectItem(pJsonRoot,"seatbeltIsUsed");
        cJSON *pspeedSelectAdress = cJSON_GetObjectItem(pJsonRoot,"speedSelect");
        cJSON *pSpeedAdress = cJSON_GetObjectItem(pJsonRoot,"ioSpeed");

        esp_err_t err;

        err = nvs_open("config",NVS_READWRITE, &my_handle);

        dlen = sizeof(key);
        nvs_get_str(my_handle, "inikey", key, &dlen);

        if(err != ESP_OK){
            free(receiveData);
            receiveData = NULL;
            return;
        }else{
            if(!pKeyAdress){
                data[len-1] = '\0';
                handle_buffer(&data[1],len-1);
                free(receiveData);
                receiveData = NULL;
                return;
            }else{
                if (cJSON_IsString(pKeyAdress))
                {
                    strcpy(value, pKeyAdress->valuestring);
                }
            }

            if(strcmp(value,keyval) != 0 && strcmp(value,key) != 0){
                free(receiveData);
                receiveData = NULL;
                return ;
            }

            /* NEWKEY */
            if (!pNewKeyAdress){
                ;
            }
            else
            {
                if (cJSON_IsString(pNewKeyAdress))
                {
                    strcpy(value, pNewKeyAdress->valuestring);
                    err = nvs_set_str(my_handle,"inikey",value);
                }
            }


            /* SSID */
            if (!pSsidAdress){
                ;
            }
            else
            {
                if (cJSON_IsString(pSsidAdress))
                {
                    strcpy(value, pSsidAdress->valuestring);
                    err = nvs_set_str(my_handle,"ssid",value);
                }

            }
            
            /* password */
            if (!pPasswordAdress){ 
                ;
            }
            else
            {
                if (cJSON_IsString(pPasswordAdress))
                {
                    strcpy(value, pPasswordAdress->valuestring);
                    err = nvs_set_str(my_handle,"password",value);
                }
            }

            /*can bps*/
            if (!pCanAdress){ 
                ;
            }else{
                intvalue = pCanAdress->valueint;
                err = nvs_set_i32(my_handle,"can_bps",intvalue);
            }
            
            /*485 bps*/
            if (!p485Adress){ 
                ;
            }else{
                intvalue = p485Adress->valueint;
                err = nvs_set_i32(my_handle,"485_bps",intvalue);
            }

            /*serIP*/
            if (!pserIPAdress){ 
                ;
            }else{
                if (cJSON_IsString(pserIPAdress))
                {
                    strcpy(value, pserIPAdress->valuestring);
                    err = nvs_set_str(my_handle,"serip",value);
                }
            }
            
            /*serPort*/
            if (!pserPortAdress){
                ;
            }else{
                intvalue = pserPortAdress->valueint;
                err = nvs_set_i32(my_handle,"serport",intvalue);
            }

            /*psbSensorIdAdress*/
            if (!psbSensorIdAdress){ 
                ;
            }else{
                if (cJSON_IsString(psbSensorIdAdress))
                {
                    strcpy(value, psbSensorIdAdress->valuestring);
                    
                    err = nvs_set_str(my_handle,"seatbeltSensorId",value);
                }
            }

            /*psbIsUsedAdress*/
            if (!psbIsUsedAdress){ 
                ;
            }else{
                if (cJSON_IsString(psbIsUsedAdress))
                {
                    intvalue = psbIsUsedAdress->valueint;
                    err = nvs_set_u8(my_handle,"seatbeltIsUsed",intvalue);
                }
            }

            /*pspeedSelectAdress*/
            if (!pspeedSelectAdress){
                ;
            }else{
                if (cJSON_IsString(pspeedSelectAdress))
                {
                    intvalue = pspeedSelectAdress->valueint;
                    err = nvs_set_u8(my_handle,"speedSelect",intvalue);
                }
            }

            /*pSpeedAdress*/
            if (!pSpeedAdress){
                ;
            }else{
                if (cJSON_IsString(pSpeedAdress))
                {
                    intvalue = pSpeedAdress->valueint;

                    err = nvs_set_u64(my_handle,"speedfix",avgrate * intvalue);
                }
            }

            nvs_commit(my_handle);
            nvs_close(my_handle);
        }
    }
    free(receiveData);
    receiveData = NULL;

    my_restart = 1;
}
